sortlistmodel: Properly compute runs
authorBenjamin Otte <otte@redhat.com>
Tue, 21 Jul 2020 02:50:05 +0000 (04:50 +0200)
committerBenjamin Otte <otte@redhat.com>
Wed, 22 Jul 2020 12:30:49 +0000 (14:30 +0200)
When updating a (partially) sorted model, take the known runs for the
existing sort and apply them to the new sort. That way, we don't have to
check the whole model again.

Benchmarks:

      appending half the items to a model of strings
                        old      new
      512,000 items   437ms    389ms
    1,024,000 items  1006ms    914ms

      appending 10% of the items to a model of strings
                        old      new
      512,000 items   206ms    132ms
    1,024,000 items   438ms    301ms

      appending 1 item to a model of strings
                        old      new
       64,000 items   1.8ms   0.00ms
      512,000 items     ---   0.01ms

gtk/gtksortlistmodel.c

index 5fa310532324dab6d29de32c5c5c0cc5a3b1fbb8..49fa234e14a92365a2eebe4fb87c61b132ca563b 100644 (file)
@@ -414,6 +414,7 @@ gtk_sort_list_model_update_items (GtkSortListModel *self,
                                   guint            *unmodified_end)
 {
   guint i, n_items, valid;
+  guint run_index, valid_run, valid_run_end, run_end;
   guint start, end;
   gpointer *old_keys;
 
@@ -445,28 +446,50 @@ gtk_sort_list_model_update_items (GtkSortListModel *self,
 
   /* then, update the positions */
   valid = 0;
-  for (i = 0; i < n_items; i++)
+  valid_run = 0;
+  valid_run_end = 0;
+  run_index = 0;
+  run_end = 0;
+  for (i = 0; i < n_items;)
     {
-      guint pos = ((char *) self->positions[i] - (char *) old_keys) / self->key_size;
-
-      if (pos >= position + removed)
-        pos = pos - removed + added;
-      else if (pos >= position)
-        { 
-          start = MIN (start, valid);
-          end = n_items - i - 1;
-          continue;
+      if (runs[run_index] == 0)
+        {
+          run_end = n_items;
+          valid_run_end = G_MAXUINT;
+        }
+      else
+        {
+          run_end += runs[run_index++];
         }
 
-      self->positions[valid] = key_from_pos (self, pos);
-      valid++;
-    }
-  self->positions = g_renew (gpointer, self->positions, n_items - removed + added);
+      for (; i < run_end; i++)
+        {
+          guint pos = ((char *) self->positions[i] - (char *) old_keys) / self->key_size;
+
+          if (pos >= position + removed)
+            pos = pos - removed + added;
+          else if (pos >= position)
+            { 
+              start = MIN (start, valid);
+              end = n_items - i - 1;
+              continue;
+            }
 
-  /* FIXME */
-  runs[0] = 0;
+          self->positions[valid] = key_from_pos (self, pos);
+          valid++;
+        }
 
+      if (valid_run_end < valid)
+        {
+          runs[valid_run++] = valid - valid_run_end;
+          valid_run_end = valid;
+        }
+    }
+  g_assert (i == n_items);
   g_assert (valid == n_items - removed);
+  runs[valid_run] = 0;
+
+  self->positions = g_renew (gpointer, self->positions, n_items - removed + added);
 
   self->n_items = n_items - removed + added;